#ifndef _SHAREDQUEUE_
#define _SHAREDQUEUE_

#include <boost/thread/thread.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/thread/condition.hpp>
#include <queue>
#include <iostream>
#include "SwafStructs.h"
using namespace std;
using namespace boost;
//extern boost::mutex io_mutex;
//#define DEBUG
#define MUTEX

template <class T>
class SharedQueue
{
private:
  #ifdef MUTEX
  boost::mutex mutex;
  boost::condition cond;
  #endif
public:
	queue<T> myQueue;
	SharedQueue();
	~SharedQueue();
	void push(T&);
	void pop(T&);
	T& front();
	T& back();
	int size();
	bool empty();
};

//===========================================================================
//
// Constructor
//
template<class T> SharedQueue<T>::SharedQueue()
{
}


//===========================================================================
//
// Destructor
//
template<class T> SharedQueue<T>::~SharedQueue()
{
}

//===========================================================================
//
// Reutrn Queue Size
//
template<class T> int SharedQueue<T>::size()
{
	return myQueue.size();
}

//===========================================================================
//
// Reutrn TRUE when queue is empty
//
template<class T> bool SharedQueue<T>::empty()
{
	return myQueue.empty();
}

//===========================================================================
//
//	push(T& elem):
//
// Add element to the end of shared queue
//
template<class T> void SharedQueue<T>::push(T& elem)
{
	#ifdef MUTEX
	boost::mutex::scoped_lock lock(mutex);
	bool was_empty=this->empty();
	#endif

	myQueue.push(elem);

	#ifdef DEBUG
	{
		cout<<"PUSH"<<endl;
		cout<<"SharedQueue size: "<<this->size()<<endl;
	}
	#endif

	#ifdef MUTEX
	if(was_empty)
	{
		cond.notify_one();
	}
	#endif
}


//===========================================================================
//
// Remove element from the head of shared queue
//
template<class T> void SharedQueue<T>::pop(T& elem)
{
//	while( this->empty() )
//		usleep(10000);

	#ifdef MUTEX
	boost::mutex::scoped_lock lock(mutex);
	if (this->empty())
	{
		cond.wait(lock); // wait only if the Q is empty !!!
	}
	#endif


	elem=myQueue.front();
	myQueue.pop();

	#ifdef DEBUG
	{
		cout<<"POP"<<endl;
		cout<<"SharedQueue size: "<<this->size()<<endl;

	}
	#endif
}


#endif
